﻿//-----------------------------------------------------------------------
// <copyright file="SQLiteConnection.cs" company="NextLine Software">
//     Copyright (c) NextLine Software. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace NextLine.Data.SQLite
{
    using System;
    using System.Data;
    using System.Text;
    using NextLine.Data.SQLite.Wrapper;

    public partial class SQLiteConnection : IDbConnection
    {
        private string connectionString;
        private ConnectionState connectionState;
        private Sqlite3.sqlite3 databaseHandle;
        private string callbackErrorMessage;

        public SQLiteConnection()
        {
            this.connectionState = ConnectionState.Closed;
        }

        public SQLiteConnection(string connectionString)
            : this()
        {
            this.connectionString = connectionString;
        }

        public string ConnectionString
        {
            get
            {
                return this.connectionString;
            }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException();
                }

                if (value.Length == 0)
                {
                    throw new ArgumentException("ConnectionString must be a valid database name.");
                }

                if (this.State != ConnectionState.Closed)
                {
                    throw new InvalidOperationException("ConnectionString can only be set on Closed connections.");
                }

                this.connectionString = value;
            }
        }

        public int ConnectionTimeout
        {
            get
            {
                return 0;
            }
        }

        public string Database
        {
            get
            {
                return this.connectionString;
            }
        }

        public ConnectionState State
        {
            get
            {
                return this.connectionState;
            }
        }

        internal Sqlite3.sqlite3 DatabaseHandle
        {
            get
            {
                return this.databaseHandle;
            }
        }

        public IDbTransaction BeginTransaction()
        {
            return this.BeginTransaction(IsolationLevel.Unspecified);
        }

        public IDbTransaction BeginTransaction(IsolationLevel il)
        {
            return new SQLiteTransaction(this, il);
        }

        public void ChangeDatabase(string databaseName)
        {
            throw new NotSupportedException();
        }

        public void Close()
        {
            if (this.connectionState != ConnectionState.Closed)
            {
                Sqlite3.sqlite3_close(this.databaseHandle);
                this.databaseHandle = null;
                this.connectionState = ConnectionState.Closed;
            }
        }

        public IDbCommand CreateCommand()
        {
            return new SQLiteCommand(string.Empty, this);
        }

        public void Open()
        {
            if (this.connectionState != ConnectionState.Closed)
            {
                throw new InvalidOperationException("SQLiteConenction must be in a closed state before opening.");
            }

            if (Sqlite3.sqlite3_open(this.connectionString, ref this.databaseHandle) != Sqlite3.SQLITE_OK)
            {
                throw new SQLiteException("Could not open database file: " + this.connectionString);
            }

            string errorMessage = string.Empty;
            if (Sqlite3.sqlite3_exec(this.databaseHandle, "PRAGMA journal_mode=PERSIST", (Sqlite3.dxCallback)this.SQLiteErrorCallback, null, ref errorMessage) != Sqlite3.SQLITE_OK)
            {
                Sqlite3.sqlite3_close(this.databaseHandle);
                this.databaseHandle = null;
                throw new SQLiteException("Cannot set journal mode to PERSIST: " + this.connectionString);
            }

            this.connectionState = ConnectionState.Open;
        }

        public void Dispose()
        {
            this.Close();
        }

        private int SQLiteErrorCallback(object arg, long count, object argumentsArray, object columnsArray)
        {
            int i;
            string[] arguments = (string[])argumentsArray;
            string[] columns = (string[])columnsArray;

            StringBuilder sb = new StringBuilder();
            for (i = 0; i < count; i++)
            {
                sb.AppendLine(columns[i] + " = " + arguments[i]);
            }

            this.callbackErrorMessage = sb.ToString();
            return 0;
        }
    }
}
